from django.shortcuts import render
from gevent.time import sleep

from apps.goods.models import SKU

# Create your views here.
"""
需求
    提交订单页面展示
前端
    发送一个axios请求来获取 地址信息和购物车中选中商品的信息
后端
    请求      必须是登录用户才能访问
    业务逻辑    地址信息，购物车中选中的商品信息
    响应      JSON
    路由  
                GET   orders/settlement/
    步骤
        1.获取用户信息
        2.地址信息
            2.1 查询用户的地址信息
            2.2 将对象转换为字典数据
        3.购物车中选中的商品信息
            3.1 连接redis
            3.2 hash
            3.3 set
            3.4 重新组织一个 选中的信息
            3.5 根据商品id 查询商品的具体信息
            3.6 需要将对象数据转换为字典数据
"""
from django.views import View
from uitls.views import LoginRequiredJSONMixin
from apps.users.models import Address
from django_redis import get_redis_connection
from django.http import JsonResponse
class OrderSettlementView(LoginRequiredJSONMixin,View):
    def get(self,requset):
        # 1.获取用户信息
        user = requset.user
        # 2.地址信息
        #     2.1 查询用户的地址信息
        addresses = Address.objects.filter(is_deleted=False)
        #     2.2 将对象转换为字典数据
        addresses_list=[]
        for address in addresses:
            addresses_list.append({
                'id': address.id,
                'province': address.province.name,
                'city': address.city.name,
                'district': address.district.name,
                'place': address.place,
                'receiver': address.receiver,
                'mobile': address.mobile
            })
        # 3.购物车中选中的商品信息
        #     3.1 连接redis
        redis_cli = get_redis_connection('carts')
        pipeline=redis_cli.pipeline()
        #     3.2 hash
        #不能再这里接收redis的响应 all=pipeline.hgetall()错误的 应该子exexcute（）接收
        pipeline.hgetall('carts_%s'%user.id)
        #     3.3 set
        pipeline.smembers('selected_%s'%user.id)
        result=pipeline.execute()
        #result = [hash结果，set结果]
        sku_id_counts = result[0]
        selected_ids = result[1]
        #     3.4 重新组织一个 选中的信息
        #selected_carts = {sku_id:count}
        selected_carts ={}
        for sku_id in selected_ids:
            selected_carts[int(sku_id)]=int(sku_id_counts[sku_id])
        #     3.5 根据商品id 查询商品的具体信息
        sku_list=[]
        for sku_id,count in selected_carts.items():
            sku = SKU.objects.get(pk=sku_id)
            #     3.6 需要将对象数据转换为字典数据
            sku_list.append({
                'id': sku.id,
                'name': sku.name,
                'default_image_url': sku.default_image.url,
                'count': count,
                'price': sku.price
            })
        from decimal import Decimal
        freight = Decimal(10)
        context ={
            'skus':sku_list,
            'addresses':addresses_list,
            'freight':freight,
        }
        return JsonResponse({'code':0,'errmsg':'ok','context':context})

"""
需求:
    点击提交订单，生成订单
前端：
    发送axios请求 POST 携带 地址id，支付方式，用户的session信息（cookie）
    不用携带 总金额，商品id和数量 （后端可以自己获取到）
后端：
    请求      接受请求，验证数据
    业务逻辑    数据入库
    响应      返回响应
    路由      POST
    步骤
        1.接受请求  user,address_id,pay_method
        2.验证数据
        order_id 主键（自己生成的）
        支付状态有支付方式决定
        总数量，总金额 = 0
        运费
        3.数据入库  生成订单（订单基本信息表和订单商品信息表）
            3.1 先保存订单基本信息
            3.2在保存订单商品信息
             连接redis
             获取hash
             获取set
             重写组织一个数据，这个数据是选中的商品信息
             根据选中的商品id进行查询
             判断库存是否充足
             如果充足，则库存减少，储量增加
             如果不充足，下单失败
             累加总数量总金额
             保存订单商品信息
        更新订单的总金额和总数量    
        4.返回响应
"""
import json
from datetime import datetime
import datetime
from django_redis import get_redis_connection
from django.utils import timezone
from django.db import transaction
from apps.orders.models import OrderInfo,OrderGoods
class OrderCommitView(LoginRequiredJSONMixin,View):
    def post(self,request):
        user = request.user
        # 1.接受请求  user,address_id,pay_method
        data = json.loads(request.body.decode())
        address_id = data.get('address_id')
        pay_method = data.get('pay_method')
        # 2.验证数据
        if not all([address_id,pay_method]):
            return JsonResponse({'code':400,'errmsg':'参数不全'})
        try:
            address = Address.objects.get(id =address_id)
        except Address.DoesNotExist:
            return JsonResponse({'code': 400, 'errmsg': '参数不正确'})
        # if pay_method not in [1,2]:代码这样写没错但是可读性不强，1，2没有明确的意思
        #     return JsonResponse({'code': 400, 'errmsg': '参数不正确'})
        if pay_method not in [OrderInfo.PAY_METHODS_ENUM['CASH'],OrderInfo.PAY_METHODS_ENUM['ALIPAY']]:
            return JsonResponse({'code': 400, 'errmsg': '参数不正确'})
        # order_id 主键（自己生成的）
        # datetime.strftime()
        # Year
        # month
        # day
        # Hour
        # Minute
        # Second
        #%f 微秒
        # timezone.localtime() 2025-10-10 16:22:01
        order_id =timezone.localtime().strftime('%Y%m%d%H%M%S%f') + '%09d'%user.id
        # 支付状态有支付方式决定
        if pay_method==OrderInfo.PAY_METHODS_ENUM['CASH']:
            status=OrderInfo.ORDER_STATUS_ENUM['UNSEND']
        else:
            status = OrderInfo.ORDER_STATUS_ENUM['UNPAID']
        # 总数量，总金额 = 0
        total_count = 0
        from decimal import Decimal
        total_amount = Decimal('0')
        # 运费
        freight = Decimal('10.00')
        with transaction.atomic():
            #事件开始点
            point = transaction.savepoint()
            # 3.数据入库  生成订单（订单基本信息表和订单商品信息表）
            #     3.1 先保存订单基本信息
            orderinfo=OrderInfo.objects.create(
                order_id=order_id,
                user=user,
                address=address,
                total_count=total_count,
                total_amount=total_amount,
                freight=freight,
                pay_method=pay_method,
                status=status
            )
            #     3.2在保存订单商品信息
            #      连接redis
            redis_cli = get_redis_connection('carts')
            #      获取hash
            sku_id_counts = redis_cli.hgetall('carts_%s'%user.id)
            #      获取set
            selected_ids=redis_cli.smembers('selected_%s'%user.id)
            #遍历选中商品id
            carts={}
            #      重写组织一个数据，这个数据是选中的商品信息
            for sku_id in selected_ids:
                carts[int(sku_id)]=int(sku_id_counts[sku_id])
            #遍历
            for sku_id,count in carts.items():
                # for i in range(10):
                while True:
                    sku = SKU.objects.get(id=sku_id)
                #      根据选中的商品id进行查询
                #      判断库存是否充足
                    if sku.stock<count:
                        #回滚点
                        transaction.savepoint_rollback(point)
                        #      如果不充足，下单失败
                        return JsonResponse({'code':400,'errmsg':'库存不足'})
                #      如果充足，则库存减少，储量增加
                #     sku.stock-=count
                #     sku.sales+=count
                #     sku.save()

                #先记录某一个数据 记录哪个数据都可以
                    old_sales=sku.sales
                    #更新的时候对比一下这个记录对不对
                    new_stock = sku.stock-count
                    new_sales = sku.sales+count
                    result=SKU.objects.filter(id=sku_id,sales=old_sales).update(stock=new_stock,sales=new_sales)
                    #result=1表示有一条记录修改成功
                    #result=0表示没有更新
                    if result==0:
                        #暂时回滚和下单失败
                        sleep(0.005)
                        continue
                        # transaction.savepoint_rollback(point)
                        # return JsonResponse({'code':400,'errmsg':'下单失败~~~~~'})
                #      累加总数量总金额
                    orderinfo.total_count+=count
                    orderinfo.total_amount+=(count*sku.price+freight)
                #      保存订单商品信息
                    OrderGoods.objects.create(
                        order=orderinfo,
                        sku=sku,
                        count=count,
                        price=sku.price
                    )
                    break
            # 更新订单的总金额和总数量
            orderinfo.save()
            #事物的提交点
            transaction.savepoint_commit(point)

        # 4.返回响应
        return JsonResponse({'code':0,'errmsg':'ok','order_id':order_id})
        pass